package com.newtouch.cq.base.starter.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.newtouch.cq.base.starter.business.entity.SysOrganization;
import com.newtouch.cq.base.starter.business.mapper.BaseSysOrganizationMapper;
import com.newtouch.cq.base.starter.business.model.UserDetailsImpl;
import com.newtouch.cq.base.starter.business.model.dto.SysOrganizationAddDTO;
import com.newtouch.cq.base.starter.business.model.dto.SysOrganizationUpdDTO;
import com.newtouch.cq.base.starter.business.model.vo.OrgTreeModel;
import com.newtouch.cq.base.starter.business.service.IBaseSysOrganizationService;
import com.newtouch.cq.base.starter.lang.util.CurrentUserUtil;
import com.newtouch.cq.lang.em.StatusEnum;
import com.newtouch.cq.lang.result.MccObjectResult;
import com.newtouch.cq.lang.util.DateUtils;
import com.newtouch.cq.mybatis.util.DbUtil;
import org.springframework.stereotype.Service;

import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统组织表 服务实现类
 * </p>
 *
 * @author Alex
 * @since 2021-08-02
 */
@Service
public class BaseSysOrganizationServiceImpl extends ServiceImpl<BaseSysOrganizationMapper, SysOrganization> implements IBaseSysOrganizationService {

    private Log log = LogFactory.get(BaseSysOrganizationServiceImpl.class);

    @Override
    public MccObjectResult<List<OrgTreeModel>> selectListTree() {
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();
        List<SysOrganization> orgList = selectAuthList(operator.getId(),operator.getOrgId());
        List<Long> orgIdList = orgList.stream().map(SysOrganization::getId).collect(Collectors.toList());

        List<OrgTreeModel> trees = getDeptTree(orgList, orgIdList,0, 0);
        return MccObjectResult.success(trees);
    }

    @Override
    public List<SysOrganization> selectAuthList(long userId, long orgId) {
        List<SysOrganization> orgList = CollUtil.newArrayList();
        SysOrganization organization = baseMapper.selectById(orgId);
        if(userId == 1l) {
            LambdaQueryWrapper<SysOrganization> ne = Wrappers.lambdaQuery(SysOrganization.class).ne(SysOrganization::getStatus, StatusEnum.DELETE.getValue());
            orgList = baseMapper.selectList(ne);
        }else {
            findDeptWithChildrenId(orgId, orgList);
            orgList.add(organization);
        }
        return orgList;
    }

    @Override
    public void deleteById(long id) {
        CurrentUserUtil.containsOrgOrThrow(id);
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();
        SysOrganization organization = new SysOrganization();
        organization.setId(id);
        organization.setStatus(StatusEnum.DELETE);
        organization.setUpdateId(operator.getId());
        organization.setUpdateName(operator.getUsername());
        organization.setUpdateTime(DateUtils.localDateTime());
        baseMapper.updateById(organization);
    }

    @Override
    public void add(SysOrganizationAddDTO dto) {
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();

        SysOrganization organization = new SysOrganization();
        BeanUtil.copyProperties(dto,organization, CopyOptions.create().ignoreNullValue());

        organization.setStatus(StatusEnum.VALID);
        organization.setCreateId(operator.getId());
        organization.setCreateName(operator.getUsername());
        organization.setCreateTime(DateUtils.localDateTime());
        organization.setUpdateId(operator.getId());
        organization.setUpdateName(operator.getUsername());
        organization.setUpdateTime(organization.getCreateTime());
        baseMapper.insert(organization);
    }

    @Override
    public void upadte(long id, SysOrganizationUpdDTO dto) {
        UserDetailsImpl operator = CurrentUserUtil.userOrThrow();
        DbUtil.containId(baseMapper,id,log);
        CurrentUserUtil.containsOrgOrThrow(id);
        SysOrganization organization = new SysOrganization();
        BeanUtil.copyProperties(dto,organization, CopyOptions.create().ignoreNullValue());
        organization.setId(id);
        organization.setUpdateId(operator.getId());
        organization.setUpdateName(operator.getUsername());
        organization.setUpdateTime(organization.getCreateTime());
        baseMapper.updateById(organization);
    }

    /**
     * 迭代查询子组织
     * @param orgId
     * @param orgList
     * @return
     */
    private  List<SysOrganization> findDeptWithChildrenId(long orgId, List<SysOrganization> orgList) {

        LambdaQueryWrapper<SysOrganization> wrapper = Wrappers.lambdaQuery(SysOrganization.class)
                .ne(SysOrganization::getStatus,StatusEnum.DELETE.getValue())
                .eq(SysOrganization::getParentId, orgId);
        List<SysOrganization> organizations = baseMapper.selectList(wrapper);

        orgList.addAll(organizations);

        organizations.parallelStream().forEach(org -> {
            findDeptWithChildrenId(org.getId(), orgList);
        });
        return orgList;
    }

    /**
     * 构建组织树
     *
     * @param orgList 组织集合
     * @param orgIdList 组织标识集合
     * @param parentId  父组织标识
     * @return
     */
    private List<OrgTreeModel> getDeptTree(List<SysOrganization> orgList,List<Long> orgIdList, int orgth, long parentId) {
        OrgTreeModel node;
        List<OrgTreeModel> trees = CollUtil.newArrayList();
        orgth++;
        for (Iterator<SysOrganization> iterator = orgList.iterator(); iterator.hasNext();) {
            SysOrganization org = iterator.next();
            node = new OrgTreeModel();
            if(org.getParentId() == parentId || !CollUtil.contains(orgIdList,org.getParentId())) {
                node.setId(org.getId());
                node.setParentId(org.getParentId());
                node.setName(org.getName());
                trees.add(node);
                iterator.remove();
            }
        }
        for (OrgTreeModel orgTree : trees) {
            List<OrgTreeModel> children = getDeptTree(orgList,orgIdList, orgth, orgTree.getId());
            orgTree.getChildren().addAll(children);
        }
        return trees;
    }
}
